Skip to main content

Procedure

Prerequisites

  • Download spectre.c from gist.github.com.
  • Recompile gem5 in the x86 instruction set. Refer to the tutorial, except instead of scons build/RISCV/gem5.opt use scons build/X86/gem5.opt.

Procedure

Compile the spectre.c code

You need to perform a bit more specific of a command than normal:

gcc -g spectre.c -o spectre -static

This makes the following modifications to the compiled code:

  • -g add debug symbols
  • -static statically link libraries

This will produce a standalone binary that you can use in the gem5 simulator. In order to run this binary with gem5, we provide the spectre_workload in system.py

Modify the two_level.py config file

  • Change X86TimingCPU to X86O3CPU(branchPred=LTAGE())

Generate a Log File

The first task will be to generate a log-file that shows the passage of instructions through the pipeline.

  1. Use the following command as tested above then hit ctrl-c after the first 2 letters. Record the tick number that the simulator ended at. For example 13062347000

    nice -n 19 $GEM_PATH/build/X86/gem5.opt configs/learning_gem5/part1/two_level.py spectre
  2. Run gem5 with the debug flag O3PipeView enabled.

warning

Make sure the debug-start tick matches the tick from step 1.

nice -n 19 $GEM_PATH/build/X86/gem5.opt --debug-flags=O3PipeView --debug-file=pipeview.txt --debug-start=13062347000 configs/learning_gem5/part1/two_level.py spectre
  1. Watch the output and stop execution with ctrl-c after two more letters appeared than in step 1. This will create at least two instances of speculative side effects we can observe.

  2. Run the pipeline viewer with the generated trace file.

tip

The -w option specifies the width of the output file so depending on the size of your terminal you may wish to choose a larger or smaller value.

$GEM_PATH/util/o3-pipeview.py --store_completions m5out/pipeview.txt --color -w 100

  1. Now finally use the following command to view the generated file showing the instructions moving through the pipeline:

    less -r o3-pipeview.out

note

The timeline section shows time moving from left to right and shows instructions going through the stages of the pipeline with letters indicating the time they entered each stage and dots for each cycle they remain in that stage. For example f....dn.p....ic..r would represent fetch, wait 4 cycles, decode, rename,wait 1, dispatch, wait 4, issue, commit, wait 2, and retire. l and s are used to denote load finishing and store finishing respectively.

The tick column shows the tick of the simulator. The pc.upc column shows the instructions along with their addresses. The disasm column shows the assembly instructions being executed.

note

time will wrap around if an instruction runs out of room in the timeline column. For example in the following timeline it appears as though issuing, committing and retiring came before fetch, decode and renaming but this is due to the wraparound.

[............ic......r...........................................f.............................dn....]

Match Vulnerable Instructions

Now that the log-file is created we want to match up the instructions executed to the vulnerable section of spectre.c code. This will be the next task:

info

The binary generated during installation was compiled with the -g flag so that it can be disassembled alongside the source. Therefore we can use the following command to create the disassembly:

objdump -S spectre > spectreX86.s
  1. Now the disassembly can be examined to find the instruction addresses where speculation is used to leak victim secrets.

    tip

    I would recommend reading over the spectre.c source to determine the relevant section and then examine spectreX86.s to find the address of the relevant instructions.

  2. Once the section of code has been located, write down the address of the relevant instructions. An address looks like 400c12:

  3. With this address we can search the log-file that was generated earlier to find the part of the log-file where leaking occured.

    less commands

    When in the less program, you can use vim-style searching:

    If we wanted to search for our example address, you can type/400c12 (/ + your search string) and press enter. This will search the log-file for the string 400c12.

    If you are in the correct section of the log-file you should see many instructions that contain lines like:

    [=====================================f============dn==ic=================================================]

    This means that the instruction was squashed due to a misprediction.

  4. Attach with your report the disassembly of the vulnerable code victim_function taken from spectreX86.s and call it vuln.s. Further attach the section from the o3-pipeview.out that corresponds to addresses in vuln.s that shows the squashed instructions in the vulnerable section. Call this excerpt pipeview-spec.out

  5. (2 points) Meeting notes. See the collaboration requirements for what to include.


Postscript

The attack discussed in this lab is known as Spectre Variant 1. There are many other variants that in some way exploit speculation to read values that are off-limits. Some variants of Spectre are significantly much more difficult to mitigate. In the case of variant 1 it is possible to patch by recompiling sensitive applications to avoid the structure below:

if(index < len)
array[expr(index)] //leaky

For example a fence instruction can be inserted to prevent speculation as below. Fence operates by preventing any instructions from being issued until all older instructions have been retired. Thus the access to array can only happen if index is within bounds.

if(index < len){
fence()
array[expr(index)] //safe
}